<template>
  <div v-if="slots.search || slots.action" class="flex justify-between py-16">
    <form class="flex" @submit.prevent="handleSearch()">
      <n-space wrap :size="[16, 16]">
        <slot name="search" />
        <div v-if="slots.search" class="flex-shrink-0">
          <n-button ghost type="primary" @click="handleReset">
            <i class="i-fe:rotate-ccw mr-4" />
            重置
          </n-button>
          <n-button attr-type="submit" class="ml-20" type="primary">
            <i class="i-fe:search mr-4" />
            搜索
          </n-button>
        </div>
      </n-space>
    </form>
    <div class="flex-shrink-0">
      <n-space wrap :size="[16, 16]">
        <slot name="action"></slot>
      </n-space>
    </div>
  </div>
  <n-data-table
    class="crud-table"
    :style="{ height: `${height}px` }"
    :max-height="height"
    :remote="remote"
    :loading="loading"
    :scroll-x="scrollX"
    :columns="treatedColumns"
    :data="tableData"
    :row-key="(row) => row[rowKey]"
    :pagination="isPagination ? pagination : false"
    v-bind="attrs"
    flex-height
    @update:checked-row-keys="onChecked"
  />
</template>

<script setup lang="jsx">
import { usePermissionStore } from '@/store'
import { NDataTable } from 'naive-ui'
import { utils, writeFile } from 'xlsx'
defineOptions({ name: 'MyTable' })
const attrs = useAttrs()
const slots = useSlots()
const props = defineProps({
  /**
   * @remote true: 后端分页  false： 前端分页
   */
  remote: {
    type: Boolean,
    default: true,
  },
  /**
   * @remote 是否分页
   */
  isPagination: {
    type: Boolean,
    default: true,
  },
  scrollX: {
    type: Number,
    default: 1200,
  },
  rowKey: {
    type: String,
    default: 'id',
  },
  columns: {
    type: Array,
    required: true,
  },
  queryItems: {
    type: Object,
    default() {
      return {}
    },
  },
  getData: {
    type: Function,
    required: true,
  },
  selection: {
    type: Boolean,
    default: false,
  },
  index: {
    type: Boolean,
    default: false,
  },
  height: {
    type: Number,
    default: 650,
  },
  autoLoad: {
    type: Boolean,
    default: true,
  },
  queryFormat: {
    type: Function,
    default: (e) => e,
  },
  tooltipWidth: {
    type: Number,
    default: 300,
  },
  listKey: {
    type: String,
    default: '',
  },
})

const emit = defineEmits(['update:queryItems', 'onChecked', 'onDataChange', 'onReset'])
const { hasPermission } = usePermissionStore()
const treatedColumns = computed(() => {
  const selectionItem = props.selection ? [{ type: 'selection', fixed: 'left' }] : []
  const indexItem = props.index
    ? [
        {
          title: '序号',
          width: 80,
          key: 'index',
          render: (_, index) => index + 1,
        },
      ]
    : []
  return [
    ...selectionItem,
    ...indexItem,
    ...props.columns.map((item) => ({
      ...item,
      ellipsis: {
        tooltip: {
          style: {
            maxWidth: `${props.tooltipWidth}px`,
          },
        },
      },
    })),
  ]
})
const loading = ref(false)
const initQuery = { ...props.queryItems }
const tableData = ref([])
const pagination = reactive({
  page: 1,
  pageSize: 10,
  itemCount: 0,
  showSizePicker: true,
  showQuickJumper: true,
  pageSizes: [10, 20, 30, 40],
  onChange: (currentPage) => {
    pagination.page = currentPage
    if (props.remote) {
      handleQuery()
    }
  },
  onUpdatePageSize: (pageSize) => {
    pagination.pageSize = pageSize
    if (props.remote) {
      handleQuery()
    }
  },
  prefix: () => (
    <div>
      共{pagination.itemCount}条记录，每页显示{pagination.pageSize}条。
    </div>
  ),
  suffix: () => '页',
})
onBeforeMount(() => {
  props.autoLoad && handleQuery()
})
async function handleQuery() {
  if (props.listKey && !hasPermission(props.listKey)) return
  try {
    loading.value = true
    let paginationParams = {}
    // 如果非分页模式或者使用前端分页,则无需传分页参数
    if (props.isPagination && props.remote) {
      paginationParams = { page: pagination.page, limit: pagination.pageSize }
    }
    const other = props.queryFormat(props.queryItems)
    const { data } = await props.getData({
      ...other,
      ...paginationParams,
    })
    tableData.value = data?.records || data
    pagination.itemCount = Number(data.total ?? data.length)
  } catch (error) {
    tableData.value = []
    pagination.itemCount = 0
  } finally {
    emit('onDataChange', tableData.value)
    loading.value = false
  }
}
function handleSearch() {
  pagination.page = 1
  handleQuery()
}
async function handleReset() {
  const queryItems = { ...props.queryItems }
  for (const key in queryItems) {
    queryItems[key] = null
  }
  emit('update:queryItems', { ...queryItems, ...initQuery })
  await nextTick()
  pagination.page = 1
  emit('onReset')
  handleQuery()
}
function onChecked(rowKeys) {
  if (props.columns.some((item) => item.type === 'selection')) {
    emit('onChecked', rowKeys)
  }
}
function handleExport(columns = props.columns, data = tableData.value) {
  if (!data?.length) return $message.warning('没有数据')
  const columnsData = columns.filter((item) => !!item.title && !item.hideInExcel)
  const thKeys = columnsData.map((item) => item.key)
  const thData = columnsData.map((item) => item.title)
  const trData = data.map((item) => thKeys.map((key) => item[key]))
  const sheet = utils.aoa_to_sheet([thData, ...trData])
  const workBook = utils.book_new()
  utils.book_append_sheet(workBook, sheet, '数据报表')
  writeFile(workBook, '数据报表.xlsx')
}

defineExpose({
  handleSearch,
  handleQuery,
  handleReset,
  handleExport,
})
</script>
<style lang="scss" scoped>
:deep(.n-data-table__pagination) {
  position: relative;
  .n-pagination-prefix {
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    font-size: 14px;
    color: #686f7c;
  }
}
</style>
